from pyparsing import *

class Setting(object):
    def __init__(self, name, value):
        self.name = name
        self.value = value
        
    def __repr__(self):
        return "%s:%s;" % (self.name, self.value)
        
class Document(object):
    def __init__(self, name, content):
        self.name = name
        self.content = content
        
    def __repr__(self):
        return "%s {\n%s\n}\n" % (self.name, "\n".join(["\t%s" % e for e in self.content]))
                
class Grammar(object):
    def __init__(self):
        name =  Combine(Word(alphas) + Optional(Word(alphanums + "_")))
        
        integerValue = Word("+-", nums)
        integerValue.setParseAction(lambda t: int(t[0]))

        floatValue = Regex(r'\d+(\.\d*)?([eE]\d+)?')
        floatValue.setParseAction(lambda t: float(t[0]))
        
        stringValue = QuotedString(quoteChar='"', unquoteResults=True) | Regex(r'[^;]+')
        
        colorValue = Word("#", alphanums)
        
        value = integerValue | floatValue | colorValue | stringValue
        
        setting = name.setResultsName("name") + ":" + value.setResultsName("value") + ";"
        setting.setParseAction(lambda t: Setting(t.name, t.value))
        
        blockContents = Forward()
        block = name.setResultsName("name") + nestedExpr('{', '}', content=blockContents).setResultsName("content")
        blockContents << (setting | block)
        block.setParseAction(lambda s, l, t: Document(t.name, list(t.content[0])))
        self.doc = blockContents
        
def processDocument(doc, parents, settings):
    for item in doc.content:
        if isinstance(item, Document):
            processDocument(item, parents + [doc.name], settings)
        else:
            fullName = "%s.%s" % (".".join(parents + [doc.name]), item.name)
            settings[fullName] = item.value
        #endif
    #endfor
    
def processString(string):
    grammar = Grammar()
    doc = grammar.doc.parseString(string)
    settings = {}
    for group in doc:
        processDocument(group, [], settings)
    return settings
        
if __name__ == "__main__":
    test = """
    foo {
        a: "test";
        b: 4;
        
        bar {
            c: 3.1459;
            d: #dddddd;
        }
    }
    """
    
    print processString(test)    
